//
// io_context_pool.cpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include "io_context_pool.hpp"
#include <stdexcept>
#include <thread>

namespace http {
namespace server {

    io_context_pool::io_context_pool(std::size_t pool_size)
      : size_(pool_size),next_io_context_(0)
    {
      if (pool_size == 0)
        throw std::runtime_error("io_context_pool size is 0");

      // Give all the io_contexts work to do so that their run() functions will not
      // exit until they are explicitly stopped.
      for (std::size_t i = 0; i < pool_size; ++i)
      {
        io_context_ptr io_context(new boost::asio::io_context);
        io_contexts_.push_back(io_context);
        work_.push_back(boost::asio::make_work_guard(*io_context));
      }
    }

    void io_context_pool::run()
    {
      // Create a pool of threads to run all of the io_contexts.
      std::vector<std::thread> threads;
      for (std::size_t i = 0; i < io_contexts_.size(); ++i)
        threads.emplace_back([this, i]{ io_contexts_[i]->run(); });

      // Wait for all threads in the pool to exit.
      for (std::size_t i = 0; i < threads.size(); ++i)
        threads[i].join();
    }

    void io_context_pool::stop()
    {
      // Explicitly stop all io_contexts.
      for (std::size_t i = 0; i < io_contexts_.size(); ++i)
        io_contexts_[i]->stop();
    }

    boost::asio::io_context& io_context_pool::get_io_context()
    {
      // Use a round-robin scheme to choose the next io_context to use.
      boost::asio::io_context& io_context = *io_contexts_[next_io_context_];

      //next_io_context_ = (next_io_context_ + 1) % size_;
      ++next_io_context_;
      if (next_io_context_ == size_)
        next_io_context_ = 0;
      
      return io_context;
    }

} // namespace server
} // namespace http
